package com.guoxue.util.oss;

import java.io.BufferedReader;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Base64;
import java.util.Date;

import javax.annotation.Resource;

import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.common.utils.DateUtil;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.sts.model.v20150401.AssumeRoleRequest;
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse.Credentials;
import com.guoxue.action.common.CreatePolicy;
import com.guoxue.action.common.ForSTSSignature;
import com.guoxue.action.common.GetServerIP;
import com.guoxue.action.common.SCSettingStaticName;
import com.guoxue.domain.OSSAKVo;
import com.guoxue.service.ICreateAKService;
import com.guoxue.util.OSSUtil;
import com.guoxue.util.codeSwitch.khb;
import com.guoxue.util.codeSwitch.zt;
/**
 * 客户端使用的ossToken的生成配置(唯一实例)
 * 
 * @author zt
 *
 */
@Component
public class ClientTokenConfig {
	@Resource
	private OSSUtil ossUtil;
	@Resource
	private ForSTSSignature forSTSSignature;
	@Resource
	private ICreateAKService createAKService;
	@Resource
	private CreatePolicy createPolicy;
	// private static final long serialVersionUID = 5522372203700422672L;
	// 目前只有"cn-hangzhou"这个region可用, 不要使用填写其他region的值
	private static final String REGION_CN_HANGZHOU = "cn-hangzhou";
	private static final String STS_API_VERSION = "2015-04-01";

	private static final String CONFIG_FILE_NAME = "config.json";
	// private static final String POLICY_FILE_NAME = "PolicyFile";

	private final String accessKeyId;
	private final String accessKeySecret;
	private final String roleArn;
	private final long durationSeconds;

	//private final String policy;
	private final ProtocolType protocolType;

	private ClientTokenConfig() {
		String configFileContent;
		JSONObject configJsonObj;

		configFileContent = ReadJsonFileContent(this.getClass().getResource("/").getPath() + CONFIG_FILE_NAME);
		configJsonObj = JSONObject.parseObject(configFileContent);

		// 只有 RAM用户（子账号）才能调用 AssumeRole 接口
		// 阿里云主账号的AccessKeys不能用于发起AssumeRole请求
		// 请首先在RAM控制台创建一个RAM用户，并为这个用户创建AccessKeys
		accessKeyId = configJsonObj.getString("AccessKeyID");
		accessKeySecret = configJsonObj.getString("AccessKeySecret");
		zt.ta.question(); // 下面这句注释是什么意思?
		// RoleArn 需要在 RAM 控制台上获取
		roleArn = configJsonObj.getString("RoleArn");
		durationSeconds = configJsonObj.getLong("TokenExpireTime");
		// 此处必须为 HTTPS:
		protocolType = ProtocolType.HTTPS;
	}
	/**
	 * 获取临时的url请求的token
	 * @param roleSessionName
	 * @param bucket 需要访问资源的oss上的bucket
	 * @param policy oss访问上的限制
	 * @return
	 *@author kanghongbo
	 *@date 2016年11月15日下午3:42:32
	 */
	public OSSAKVo assumeRole(String roleSessionName,String bucket,String policy,OSSAKVo aliResponseJson,int keyType,String localUrl) {
		try {
			// 创建一个 Aliyun Acs Client, 用于发起 OpenAPI 请求
			IClientProfile profile = DefaultProfile.getProfile(REGION_CN_HANGZHOU, accessKeyId, accessKeySecret);
			DefaultAcsClient client = new DefaultAcsClient(profile);
			// 创建一个 AssumeRoleRequest 并设置请求参数
			final AssumeRoleRequest request = new AssumeRoleRequest();
			request.setVersion(STS_API_VERSION);
			request.setMethod(MethodType.GET);
			request.setProtocol(protocolType);
			request.setRoleArn(roleArn);
			//request.setPolicy(policy);
			request.setDurationSeconds(durationSeconds);
			request.setRoleSessionName(roleSessionName);
			// 发起请求，并得到response:
			final AssumeRoleResponse response = client.getAcsResponse(request);
			final Credentials credentials = response.getCredentials();
			//生成临时token和AK
            String AccessKeyId=credentials.getAccessKeyId();
            String AccessKeySecret=credentials.getAccessKeySecret();
            String SecurityToken=credentials.getSecurityToken();
            String expiration=credentials.getExpiration();
            Long time=DateUtil.parseIso8601Date(expiration).getTime();
            //记录当前临时签名
			aliResponseJson.setAccessKeyId(AccessKeyId);;
			aliResponseJson.setAccessKeySecret(AccessKeySecret);;
			aliResponseJson.setSecurityToken(SecurityToken);;
			aliResponseJson.setHttpMethod("GET");
			aliResponseJson.setExpiration(time/1000);
			aliResponseJson.setKeyType(keyType);
			aliResponseJson.setLocalUrl(localUrl);
			createAKService.saveOSSAK(aliResponseJson);
			return aliResponseJson;
		} catch (ClientException e) {
			return aliResponseJson;
		} catch (Exception ex) {
			return aliResponseJson;
		}
	}
	/**
	 * 
	 * @param roleSessionName 审计用户
	 * @param s_fileName 上传到服务器的文件名
	 * @param bucket   上传到服务器的指定bucket
	 * @param policy  当前token的身份限制
	 * @param c_fileName  客户端本地文件名
	 * @return
	 *@author kanghongbo
	 *@date 2016年11月15日下午5:07:51
	 */
	public JSONObject assumeRole(String roleSessionName,String s_fileName,int size,String bucket,String c_fileName,String localUrl) {
		final JSONObject aliResponseJson = new JSONObject();
		String expiration ="";
		try {
	        /*---------判断是否有该请求的token存在或者15-1分钟过期与否 为保证接口调用的准确性，一分钟内的token自动放弃---------------*/
	        khb.ta.function();//后期改成存放在内存中
			OSSAKVo ossAk=createAKService.getOSSAK("POST",2);
			Long ownTime=System.currentTimeMillis()/1000;
	        if(ossAk==null){
	        	ossAk=new OSSAKVo();
	        	ossAk.setExpiration(ownTime);
	        }
	        /*---------判断是否有该请求的token存在或者15-5分钟过期与否 为保证接口调用的准确性，一分钟内的token自动放弃---------------*/
	        if((ossAk.getExpiration()-ownTime)<300){
				// 创建一个 Aliyun Acs Client, 用于发起 OpenAPI 请求
				IClientProfile profile = DefaultProfile.getProfile(REGION_CN_HANGZHOU, accessKeyId, accessKeySecret);
				DefaultAcsClient client = new DefaultAcsClient(profile);
				// 创建一个 AssumeRoleRequest 并设置请求参数
				final AssumeRoleRequest request = new AssumeRoleRequest();
				request.setVersion(STS_API_VERSION);
				request.setMethod(MethodType.POST);
				request.setProtocol(protocolType);
				request.setRoleArn(roleArn);
				//request.setPolicy(policy);
				request.setDurationSeconds(durationSeconds);
				request.setRoleSessionName(roleSessionName);
				// 发起请求，并得到response:
				final AssumeRoleResponse response = client.getAcsResponse(request);
				final Credentials credentials = response.getCredentials();
				ossAk.setAccessKeyId(credentials.getAccessKeyId());
				ossAk.setAccessKeySecret(credentials.getAccessKeySecret());
				ossAk.setSecurityToken(credentials.getSecurityToken());
				ossAk.setHttpMethod("POST");
				ossAk.setKeyType(2);
				expiration = credentials.getExpiration();
				Long expire=DateUtil.parseIso8601Date(expiration).getTime();
				
				expiration=expire+"";
				ossAk.setExpiration(expire/1000);
				createAKService.saveOSSAK(ossAk);
	        }
	        //生成临时授权上传文件的限制条件
	        String policy=createPolicy.getPolicy(s_fileName, SCSettingStaticName.CLIENT_AUDIO_LIMITSIZE, size, bucket, SCSettingStaticName.EXPIRATION_TIME);
	        byte[] binaryData = policy.getBytes("utf-8");
	        String encodedPolicy = BinaryUtil.toBase64String(binaryData);
			// 发起签名请求
	        String signature=forSTSSignature.ForPOSTSignature(ossAk.getAccessKeySecret(), encodedPolicy);
			aliResponseJson.put("status", "200");
			aliResponseJson.put("AccessKeyId",ossAk.getAccessKeyId());
			aliResponseJson.put("signature",signature);
			aliResponseJson.put("x-oss-security-token", ossAk.getSecurityToken());
			aliResponseJson.put("Expiration", new Date(ossAk.getExpiration()));
			aliResponseJson.put("s_fileName", s_fileName);
			aliResponseJson.put("bucket", bucket);
			aliResponseJson.put("c_fileName", c_fileName);
			aliResponseJson.put("policy", encodedPolicy);
			aliResponseJson.put("localUrl", localUrl);
			aliResponseJson.put("serverIP", GetServerIP.getLocalIP());
			return aliResponseJson;
		} catch (ClientException e) {
			aliResponseJson.put("status", e.getErrCode());
			return aliResponseJson;
		} catch (Exception ex) {
			return null;
		}
	}
	/**
	 * 将json格式的文本文件的内容,拼接为一个文本字符串返回
	 * 
	 * @param path
	 *            文件路径名
	 * @return
	 */
	private static String ReadJsonFileContent(String path) {
		// 从给定位置获取文件
		File file = new File(path);
		BufferedReader reader = null;
		// 返回值,使用StringBuffer
		StringBuffer data = new StringBuffer();
		//
		try {
			reader = new BufferedReader(new FileReader(file));
			// 每次读取文件的缓存
			String temp = null;
			while ((temp = reader.readLine()) != null) {
				data.append(temp);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			// 关闭文件流
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return data.toString();
	}
	// /////////////////////////////////////////////////////////////////////////////
	// --->唯一实例:
	// /////////////////////////////////////////////////////////////////////////////
	private static final ClientTokenConfig instance = new ClientTokenConfig(); // 唯一实例

	public static ClientTokenConfig getInstance() {
		return instance; // 获取唯一实例
	}
}

// /////////////////////////////////////////////////////////////////////////////
// --->
// /////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////
